package com.lisn.myexoplayer;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.HttpDataSourceException;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoListener;
import com.lisn.rxpermissionlibrary.permissions.RxPermissions;

import java.io.IOException;

import io.reactivex.Observable;
import io.reactivex.functions.Consumer;

import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getName();
    private Context context;
    private PlayerView playerView;
    private SimpleExoPlayer player;
    private SeekBar mProgressView;
    private float MAX_PROGRESS = 1000f;
    private long mTotalDuration;
    private float mSpeed = 1f;
    private TextView mTimeView;
    private int mScreenWidth;
    private SurfaceView surface_view;
    private ImageView iv_State;
    private ImageView iv_Rewind;
    private ImageView iv_Fastforward;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        getRxPermissions();
        String filePath = "file:///sdcard/AAA/VIDEO/20200520-200150.mp4";
        init(filePath);
    }

    private void init(String filePath) {
        playerView = findViewById(R.id.playerView);
        surface_view = findViewById(R.id.surface_view);
        mTimeView = findViewById(R.id.time_view);

        iv_Rewind = findViewById(R.id.iv_Rewind);
        iv_Fastforward = findViewById(R.id.iv_Fastforward);
        iv_State = findViewById(R.id.iv_State);
        iv_State.setOnClickListener(this::mClickListener);
        iv_Rewind.setOnClickListener(this::mClickListener);
        iv_Fastforward.setOnClickListener(this::mClickListener);

        mProgressView = findViewById(R.id.video_progress_view);
        mProgressView.setOnSeekBarChangeListener(mSeekBarChangeListener);


        player = new SimpleExoPlayer.Builder(context).build();
//        playerView.setPlayer(player);
//        player.setVideoSurface(surface_view.getHolder().getSurface());
        player.setVideoSurfaceView(surface_view);


        // Add a listener to receive events from the player.
        Player.EventListener eventListener = new Player.EventListener() {
            @Override
            public void onTimelineChanged(Timeline timeline, int reason) {

            }

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                switch (playbackState) {
                    case Player.STATE_BUFFERING:
                        break;
                    case Player.STATE_IDLE:
                        break;
                    case Player.STATE_READY:
                        mTotalDuration = player.getDuration();
                        Log.e(TAG, "init: mTotalDuration = " + mTotalDuration);
                        break;
                    case Player.STATE_ENDED:
                        break;
                    default:
                        break;
                }

                if (playbackState == Player.STATE_IDLE) {
                    Log.e(TAG, "onPlayerStateChanged: Player.STATE_IDLE：这是初始状态，即播放器停止和播放失败时的状态。");
                } else if (playbackState == Player.STATE_BUFFERING) {
                    Log.e(TAG, "onPlayerStateChanged: Player.STATE_BUFFERING：播放器无法立即从当前位置播放。这主要是因为需要加载更多数据。");
                } else if (playbackState == Player.STATE_READY) {
                    Log.e(TAG, "onPlayerStateChanged: Player.STATE_READY：播放器可以立即从其当前位置播放。");
                } else if (playbackState == Player.STATE_ENDED) {
                    Log.e(TAG, "onPlayerStateChanged: Player.STATE_ENDED：播放器完成了所有媒体的播放。");
                }
            }

            @Override
            public void onIsPlayingChanged(boolean isPlaying) {
                if (isPlaying) {
                    // Active playback. //主动播放。
                } else {
                    // Not playing because playback is paused, ended, suppressed, or the player
                    // is buffering, stopped or failed. Check player.getPlaybackState,
                    // player.getPlayWhenReady, player.getPlaybackError and
                    // player.getPlaybackSuppressionReason for details.

                    //由于播放暂停，结束，被抑制或播放器而无法播放
                    //正在缓冲，停止或失败。 检查player.getPlaybackState，
                    // player.getPlayWhenReady，player.getPlaybackError和
                    // player.getPlaybackSuppressionReason了解详情。
                }
            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
                if (error.type == ExoPlaybackException.TYPE_SOURCE) {
                    IOException cause = error.getSourceException();
                    if (cause instanceof HttpDataSourceException) {
                        // An HTTP error occurred. 发生HTTP错误。
                        HttpDataSourceException httpError = (HttpDataSourceException) cause;
                        // This is the request for which the error occurred. 这是发生错误的请求
                        DataSpec requestDataSpec = httpError.dataSpec;
                        // It's possible to find out more about the error both by casting and by
                        // querying the cause. 可以通过强制转换和通过查找更多有关错误的信息查询原因。
                        if (httpError instanceof HttpDataSource.InvalidResponseCodeException) {
                            // Cast to InvalidResponseCodeException and retrieve the response code,
                            // message and headers.
                            // 转换为InvalidResponseCodeException并检索响应代码，消息和标题。
                        } else {
                            // Try calling httpError.getCause() to retrieve the underlying cause,
                            // although note that it may be null.
                            //尝试调用httpError.getCause（）检索根本原因，尽管请注意它可能为null。
                        }
                    }
                }
            }

            @Override
            public void onSeekProcessed() {

            }

            @Override
            public void onPositionDiscontinuity(int reason) {
                if (reason == DISCONTINUITY_REASON_SEEK) {
                    Log.e(TAG, "onPositionDiscontinuity: 这是调用的直接结果Player.seekTo");
                }
            }
        };
        player.addListener(eventListener);

        mScreenWidth = ScreenUtils.getScreenWidth(this);

        player.addVideoListener(videoListener);


        Uri mp4VideoUri = Uri.parse(filePath);

        // 生成用于加载媒体数据的 DataSource 实例
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
                Util.getUserAgent(context, "com.lisn.myexoplayer"));
        // 这是要播放媒体的MediaSource
        MediaSource videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(mp4VideoUri);
        // 准备播放器的资源
        player.prepare(videoSource);


    }

    private void updateVideoSize(int width, int height) {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);
        surface_view.setLayoutParams(params);
    }

    VideoListener videoListener = new VideoListener() {
        @Override
        public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
            int videoWidth = mScreenWidth;
            int videoHeight = (int) ((height * videoWidth * 1.0f) / width);
            //updateVideoSize(videoWidth, videoHeight);
        }

        @Override
        public void onSurfaceSizeChanged(int width, int height) {

        }

        @Override
        public void onRenderedFirstFrame() {

        }
    };

    private void mClickListener(View view) {
        if (view == iv_State) {
            if (player.isPlaying()) {
                //参数为`true`时播放，为`false`时停止播放
                player.setPlayWhenReady(false);
                iv_State.setImageResource(R.drawable.exo_controls_play);
                mHandler.removeMessages(MSG_UPDATE_PROGRESS);
            } else {
                player.setPlayWhenReady(true);
                iv_State.setImageResource(R.drawable.exo_controls_pause);
                mHandler.sendEmptyMessage(MSG_UPDATE_PROGRESS);
            }
        } else if (view == iv_Fastforward) {
            mSpeed += 0.25f;
            if (mSpeed > 2) {
                mSpeed = 2;
            }
            changeSpeed();
        } else if (view == iv_Rewind) {
            mSpeed -= 0.25f;
            if (mSpeed < 0) {
                mSpeed = 0.25f;
            }
            changeSpeed();
        }
    }

    private void changeSpeed() {
        Log.e(TAG, "changeSpeed: mSpeed=" + mSpeed);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                PlaybackParameters parameters = new PlaybackParameters(mSpeed);
                player.setPlaybackParameters(parameters);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //region updateVideoProgress
    private static final int MSG_UPDATE_PROGRESS = 1;
    private static final int INTERVAL = 800;
    private WeakHandler mHandler = new WeakHandler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (msg.what == MSG_UPDATE_PROGRESS) {
                updateVideoProgress();
            }
            return true;
        }
    });

    private void updateVideoProgress() {
        long currentPosition = player.getCurrentPosition();
        long totalDuration = mTotalDuration;

        String timeStr = Utility.getVideoTimeString(currentPosition) + "/" + Utility.getVideoTimeString(totalDuration);
        mTimeView.setText(timeStr);
        mTimeView.setVisibility(View.VISIBLE);
        int progress = (int) (currentPosition * 1.0f / totalDuration * MAX_PROGRESS);
        mProgressView.setProgress(progress);
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PROGRESS, INTERVAL);

    }
    //endregion


    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            if (player != null) {
                mHandler.removeMessages(MSG_UPDATE_PROGRESS);
            }
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (player != null) {
                int progress = mProgressView.getProgress();
                long seekPosition = (long) (progress * 1.0f / MAX_PROGRESS * mTotalDuration);
                player.seekTo(seekPosition);
                mHandler.sendEmptyMessage(MSG_UPDATE_PROGRESS);
            }
        }
    };

    private void getRxPermissions() {
        RxPermissions rxPermissions = new RxPermissions(this);
        Observable<Boolean> request = rxPermissions.request(Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.RECORD_AUDIO);
        request.subscribe(new Consumer<Boolean>() {
            @Override
            public void accept(Boolean aBoolean) throws Exception {
                if (!aBoolean) {
                    Log.e("---", "accept: 请开启相关权限");
                }

            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (player != null) {
            mHandler.removeMessages(MSG_UPDATE_PROGRESS);
            player.release();
            player = null;
        }
    }
}
